<?php

class Crud_Controller_Index extends Crud_Controller_Layer  
{
	public function indexAction() {}

	public function listAction()
	{
		$section = $this->_getSection();
		$columns = $section->getColumns();
		
		foreach ($columns  as $key => $column) {
			if (!$column->getShowInList()) {
				unset($columns[$key]);
			}
		}
		
		$this->view->columns = $columns;
		
		$select = $this->_getListSelect();
		$paginator = $this->_getPaginator($select);
		
		// Change values with Foreign key values
		$rowset = array();
		//$datetimeFilter = new Crud_Filter_Datetime();
		
		$ids = array();
		foreach ($paginator as $row) {
			$row = $row->toArray();
			foreach ($row as $key => &$value) {
				if (!isset($columns[$key])) {
					continue;
				}
				
				$column = $columns[$key];
				$value = $column->getValue($value);
			}
			
			$ids[] = $row['id'];
			$row['crud_locked'] = false;
			$rowset[ $row['id'] ] = $row; 
		}
		
		$handler = Crud_Event::getInstance()->getHandler('postFetch');
		if ($handler instanceof Crud_Event_Handler) {
			$rowset = $handler->run($rowset);
		}
		
		if ($rowset) {
			$select = AdminLockPeer::getInstance()->select();
			$select->where(AdminLockPeer::SECTION_ID, $section->getId());
			$select->where(AdminLockPeer::ROW_ID . Db_Select::SQL_IN, $ids);
			$ago = date('Y-m-d H:i:s', strtotime('-15 min'));
			$select->where(AdminLockPeer::CREATED . Db_Select::SQL_GREATER_EQUAL, $ago);
			
			
			$lockedRowset = AdminLockPeer::getInstance()->fetchAll($select);
			foreach ($lockedRowset as $lockedRow) {
				$rowId = $lockedRow->getRowId();
				
				$lUser = $lockedRow->getAdminUserRowByAdminUserId();
				if ($lUser->getLogin() != $this->_getUser()->getLogin()) {
					$lUserName = $lUser->getName() ? $lUser->getName() : $lUser->getLogin(); 
					$rowset[$rowId]['crud_locked'] = $lUserName;
				}
			}
		}
		
		//@todo добавили в виду необходимости использования view в базе данных, а там возможны пересечения уникальных id-ов
		$tmpRowset = $rowset;
		$rowset = array();
		foreach ($tmpRowset as $tmpRow) {
			$rowset[] = $tmpRow;
		}
		
		
		$this->view->rowset = $rowset;
		if (!$this->getRequest()->isXmlHttpRequest()) {
			$this->getFrontController()->setParam('noViewRenderer', true);
			$content = $this->view->render('crud/list.phtml');
			if ($section->getListViewScript()) {
				$additional = $this->view->render($section->getListViewScript());
				echo $content . $additional;
			} else {
				echo $content;
			}
		}
		
		
		
	}
	
	/**
	 * Create select query for list action by request object.
	 * 
	 * @return Zend_Db_Select
	 */
	protected function _getListSelect()
	{
		$table = $this->_getSection();
		$select = $table->getPeer()->select();
		
		$this->_runEvent('preSelect', $select);
		
		// Order condition
		$order = $this->_getCookieWrapParam('order');
		$orderType = $this->_getCookieWrapParam('orderType', 'asc');
		
		if (!$order) {
			if ($table->getKey() == 'orders') {
				$order = 'created_at';
				$orderType = 'desc';
			} else {
				$order = 'id';
				$orderType = 'desc';
			}
		}
		
		if ($table->hasColumn($order) || $order == 'id') {
			if ($order != 'id') {
				$column = $table->getColumn($order);
				if ($column->isFK()) {
					$fkTable = $column->getFKTable();
					$fkTableName = $fkTable->getTableName();
					
					if ($fkTableName != $table->getTableName()) {
						$order = $fkTableName.'.'.$fkTable->getPrimaryFKColumn();
						
						$condition = "{$table->getTableName()}.{$column->getKey()} = $fkTableName.id";
						$select->joinLeft($fkTableName, $condition, null);
					}
				}
			}
			
			$select->order("$order $orderType");
		}
		
		// Where conditions
		$search = $this->_getParam('search', array());
		foreach ($search as $column => $value) {
			if ($value === '' || $value === null) continue;
			
			if ($column == 'id') { 
				$select->where("`{$table->getTableName()}`.`id` = ?", $value);
			} else {
				$column = $table->getColumn($column);
				$columnName = "`{$table->getTableName()}`.`{$column->getKey()}`";
				if ($column->isFK()) {
					if (is_numeric($value)) {
						$select->where($columnName, $value);
					} else {
						$fkTable = $column->getFKTable();
						$fkTableName = $fkTable->getTableName();
						$alias = $fkTableName . '_' . $column->getKey();
						$columnName = "`$alias`.`{$fkTable->getPrimaryFKColumn()}`";
						$condition = "{$table->getTableName()}.{$column->getKey()} = $alias.id";
					
						$select->join(array($alias => $fkTableName), $condition, array());
						
						$value = addslashes($value);
						$value = str_replace('%', '\%', $value);
					
						$select->where("$columnName like '%$value%'");	
					}
				} else if ($column->getType() == 'tinyint' && $column->isUnsigned()) {
					$select->where($columnName, $value);
				} else {
					$value = addslashes($value);
					$value = str_replace('%', '\%', $value);
					
					$select->where("$columnName like '%$value%'");				
				}
			} 
		}
		
		$this->_runEvent('postSelect', $select);
		return $select;
	}
	
	/**
	 * Return paginator by Zend_Db_Table_Select object.
	 * 
	 * @param $select Zend_Db_Table_Select
	 * @return Zend_Paginator
	 */
	protected function _getPaginator($select)
	{
		$perPage = $this->_getCookieWrapParam('perPage', 25);
		Zend_View_Helper_PaginationControl::setDefaultViewPartial('paginator.phtml');
		
		$adapter = new Zend_Paginator_Adapter_DbTableSelect($select);
		$paginator = new Zend_Paginator($adapter);
		$paginator->setItemCountPerPage($perPage);
		$paginator->setCurrentPageNumber($this->_getParam('page'));

		$this->view->paginator = $paginator;
		return $paginator;
	}
	
	public function ajaxListAction()
	{
		$this->_ajaxOnly();
		$this->_disableView();
		$this->listAction();
		
		
		$paginator = $this->view->render('crud/list/paginator.phtml');
		$content = $this->view->render('crud/list/content.phtml');
		$data = array(
			'paginator' => $paginator,
			'content'   => $content,
		);
		
		$this->_setJson($data);
	}
	
	public function addAction()
	{
		$this->_item();
	}
	
	public function editAction()
	{
		if (!$this->_runEvent('preDispatchEdit', null)) {
			$this->_disableView();
			Debug::getInstance()->disableConsole();
			return ;
		}
		
		$this->_item();
	}
	
	public function _item()
	{
		$lastUrl = isset($_COOKIE['last_url']) ? $_COOKIE['last_url'] : null;
		if (!$lastUrl || !strstr($lastUrl, $this->_getParam('table'))) {
			$lastUrl = u(array(
				'action' => 'list', 
				'table' => $this->_getParam('table'), 
				'id' => null,
			));
		}
	
		if ($this->_getParam('crud_suggest')) {
			$this->_forward('suggest');
			return;
		}
		
		$row = $this->_getRow();
		$this->_runEvent('postLoadRow', $row);
		$form = $this->_getForm();
		$user = $this->_getUser();
		
		if ($this->_getParam('action') == 'edit') {
			$lock = $row->lock($user);
			if (!$row->isLockedBy($user)) {
				$this->view->lock = $lock;
				$this->_forward('locked');
				return ;
			}
		}
		
		// Processing exit without saving
		if ($this->_getParam('crud_exit')) {
			if ($this->_getParam('action') == 'edit') {
				$lock->delete();
			}
			
			$this->_redirect($lastUrl);
		}
		
		$this->_runEvent('preValidation', $row);
		$params = $this->_getAllParams();
		if ($this->getRequest()->isPost() && $form->isValid($params)) {
			// Start transaction and save/update row.
			$connection = Db::getConnection();
			$connection->beginTransaction();
			try {
				// Run event postSave
				$this->_runEvent('preSave', $row);
				
				$row->setForm($form);
				if ($this->_getParam('action') == 'edit') {
					$lock->delete();
				}
				
				// Run event postSave
				$this->_runEvent('postSave', $row);
				$connection->commit();
			} catch (Exception $e) {
				$message = $e->getMessage();
				if (stripos($message, 'Duplicate entry') !== false) {
					$message = 'Запись с такими параметрами уже существует';
				}
				
				if (stripos($message, 'a foreign key constraint fails') !== false) {
					$message = 'Невозможно добавить запись. Скорее всего такая запись уже существует.';
				}
				
				if (Debug::getInstance()->isDebugMode()) {
					$message = sprintf(
						'<p>Exception "<b>%s</b>" with message "<b>%s</b>" at %s line %u</p><br />',
						get_class($e), $e->getMessage(), $e->getFile(), $e->getLine()
					);
					
					$message .= '<ul>';
				    foreach (Debug_TraceHelper::getShortStacktrace($e->getTrace()) as $t) {
				        $message .= "<li>&nbsp;&nbsp;&nbsp;$t</li>";
				    }
    				$message .= '</ul>';
				}
				
				$form->addError($message);
				$connection->rollBack();
				// throw $e;
				return;
			}
			
			// Then redirect to list
			$this->_redirect($lastUrl);
			return;
		}
		
	}
	
	public function suggestAction()
	{
		$this->_disableLayout();
		$table = $this->_getSection();
		
		$suggest = $this->_getParam('crud_suggest');
		if (!$suggest || !is_array($suggest)) {
			throw new Crud_Exception('Request param crud_suggest does not exists or not an array');
		}
		
		foreach ($suggest as $value) {
			break;
		}
		
		if ($value == '') {
			return;
		}
		
		$column = $this->_getParam('column');
		if (!$table->hasColumn($column)) {
			return;
		}
		
		$column = $table->getColumn($column);
		$values = $column->getFKValues(null, $value);
		$this->view->items = $values;
		
	}
	
	public function clearValueAction()
	{
		$this->_ajaxOnly();
		$this->_disableView();
		
		$data['result'] = 'success';
		$data['message'] = '';
		try {
			$row = $this->_getRow();
			$column = $this->_getSection()->getColumn($this->_getParam('column'));
			if (!$column->isNull()) {
				throw new Exception('Невозможно удалить файл. Поле является обязательным. Попробуйте удалить всю запись или обновить файл.');	
			}
			
			$setter = $column->getSetter();
			$row->$setter(null);
			$row->save();
		} catch (Exception $e) {
			$data['result'] = 'failure';
			$data['message'] = "{$e->getMessage()} in {$e->getFile()}:{$e->getLine()}";
		}
		
		$this->_setJson($data);
	}
	
	/**
	 * Create form and run form events.
	 * 
	 * @return Crud_Form
	 */
	public function _getForm()
	{
		$section = $this->_getSection();
		$row = $this->_getRow();
		if ($row->isNew()) {
			$row = null;
		}
		
		$form = new Crud_Form($section, $row);
		$this->_runEvent('form', $form);
		$this->view->form = $form;
		
		return $form;
	}
	
	public function formAction()
	{
		$this->_disableView();
		$form = $this->_getForm();
		echo $form;
	}
	
	public function deleteAction()
	{
		$this->_disableView();
		$this->_ajaxOnly();
		
		$row = $this->_getRow();
		
		// Start transaction so we can restore all selected row when we have error
		$connection = Db::getConnection();
		$connection->beginTransaction();
		try {
			$this->_runEvent('preDelete', $row);
			
			$row->log('delete');
			$row->delete();
			$connection->commit();
			$result = 'success';
		} catch (Exception $e) {
			$connection->rollBack();
			
			$result = null;
			$matches = array();
			preg_match ("/`[a-z0-9_]+`\.`([a-z0-9_]+)`/", $e->getMessage(), $matches);
			if (isset($matches[1])) {
				$name = $matches[1];
				$blocker = AdminSectionPeer::getInstance()->findByTableName($matches[1])->current();
				if ($blocker) $name = $blocker->getName();
				$result = "Невозможно удалить запись. Связанные записи есть в разделе `$name`";
			}
			
			if (!$result) {
				if (!Debug::getInstance()->isDebugMode()) {
					$result = 'Невозможно удалить запись';
				} else {
					$result = $e->getMessage();
				}
			}
		}
		
		$this->_setJson(array('result' => $result));
	}
	

	
	protected function _getGroup($name) 
	{
		$peer = AdminSectionGroupPeer::getInstance();
		$key = md5($name);
		
		$row = $peer->fetchByKey($key);
		if (!$row) {
			$row = $peer->createRow();
			$row->setKey($key);
			$row->setName($name);
			$row->save();
		}
		
		return $row;
	}
	
}

